#!/usr/bin/env ruby

require 'net/http'
require 'uri'
require 'json'
require_relative 'run.rb'

def gitlab_api(url, body=nil)
  uri = URI.parse(url)

  header = {
    'Content-Type': 'application/json',
    'PRIVATE-TOKEN': ENV['GITLAB_TOKEN']
  }

  # Create the HTTP objects
  Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
    if body
      request = Net::HTTP::Post.new(uri.request_uri, header)
      request.body = body.to_json
    else
      request = Net::HTTP::Get.new(uri.request_uri, header)
    end

    response = http.request(request)
    raise "Request to #{url} failed: #{response.body}" unless Integer(response.code) < 400

    JSON.parse(response.body)
  end
end

def find_user_id
  return ENV["GITLAB_USER_ID"] if ENV["GITLAB_USER_ID"]

  response = gitlab_api("https://gitlab.com/api/v4/user")
  response['id']
end

def find_project_id(project_name)
  encoded_project_name = URI.encode_www_form_component(project_name)
  response = gitlab_api("https://gitlab.com/api/v4/projects/#{encoded_project_name}")

  response['id']
end

def find_tag
  return ENV["CI_COMMIT_TAG"] if ENV["CI_COMMIT_TAG"]

  capture!(%w[git tag --points-at HEAD]).chomp
end

def update_gitaly_version(project_id, tag_version)
  version = tag_version.sub(/^v/, "")

  server_version_commit = {
    "branch": "gitaly-version-#{tag_version}",
    "start_branch": "master",
    "commit_message": "Update Gitaly version to #{tag_version}",
    "actions": [{
      "action": "update",
      "file_path": "GITALY_SERVER_VERSION",
      "content": "#{version}\n"
    }]
  }

  gitlab_api("https://gitlab.com/api/v4/projects/#{project_id}/repository/commits", server_version_commit)
end

def create_mr(project_id, tag_version, assignee_id)
  anchor = 'v' + tag_version.tr('.', '')
  description = <<~MR
    Upgrade Gitaly to #{tag_version}.

    See the [Gitaly changelog](https://gitlab.com/gitlab-org/gitaly/blob/master/CHANGELOG.md##{anchor})
    for an overview of the changes.
  MR

  merge_request = {
    "source_branch": "gitaly-version-#{tag_version}",
    "target_branch": "master",
    "title": "Upgrade Gitaly to #{tag_version}",
    "assignee_id": assignee_id,
    "description": description,
    "labels": "devops::create,group::gitaly,backstage",
    "remove_source_branch": true,
    "squash": true
  }

  gitlab_api("https://gitlab.com/api/v4/projects/#{project_id}/merge_requests", merge_request)
end

def add_changelog(project_id, tag_version, merge_request_number)
  changelog_commit = {
    "branch": "gitaly-version-#{tag_version}",
    "start_branch": "gitaly-version-#{tag_version}",
    "commit_message": "Add changelog entry",
    "actions": [{
      "action": "create",
      "file_path": "changelogs/unreleased/gitaly-version-#{tag_version}.yml",
      "content": <<~HEREDOC
      ---
      title: Upgrade to Gitaly #{tag_version}
      merge_request: #{merge_request_number}
      author:
      type: changed
      HEREDOC
    }]
  }

  gitlab_api("https://gitlab.com/api/v4/projects/#{project_id}/repository/commits", changelog_commit)
end

abort "Please set GITLAB_TOKEN env var" unless ENV['GITLAB_TOKEN']

project_id = find_project_id("gitlab-org/gitlab")
tag_version = find_tag
assignee_id = find_user_id

abort "Unable to determine tag for current HEAD" unless tag_version

update_gitaly_version(project_id, tag_version)
merge_request = create_mr(project_id, tag_version, assignee_id)
add_changelog(project_id, tag_version, merge_request['iid'])

puts merge_request['web_url']
